using System;
using System.Collections.Generic;
using System.Linq;
using Agatha.Common;
using Common.Logging;
using Source.Common;
using Source.Web.FrameWork;

namespace Source.Tests.Web
{
    public class DispatcherStub : RequestDispatcher
    {
        private readonly UserManagerStub userManager;
        private List<Response> responsesToReturn = new List<Response>();
        private readonly Dictionary<string, Request> keyToRequest = new Dictionary<string, Request>();
        private readonly IFormsAuthentication formsAuthentication;

        public DispatcherStub():this(new UserManagerStub(), null){}
        public DispatcherStub(UserManagerStub userManager,  IFormsAuthentication formsAuthentication) : base(null,null)
        {
            this.userManager = userManager;
            this.formsAuthentication = formsAuthentication;
        }

        protected override void DealWithSecurityException(ExceptionInfo exceptionDetail)
        {
            if (formsAuthentication != null)
            {
                formsAuthentication.SignOut();
            }
        }

        public void SetResponsesToReturn(params Response[] responses)
        {
            responsesToReturn.AddRange(responses);
        }

        public void SetResponsesToReturn(Dictionary<string, Response> keyedResponses)
        {
            responsesToReturn.AddRange(keyedResponses.Values);

            for (int i = 0; i < keyedResponses.Keys.Count; i++)
            {
                var key = keyedResponses.Keys.ElementAt(i);

                if (key != null)
                {
                    keyToResultPositions.Add(key, i);
                }
            }
        }

        public void AddResponseToReturn(Response response)
        {
            responsesToReturn.Add(response);
        }

        public void AddResponseToReturn(string key, Response response)
        {
            responsesToReturn.Add(response);
            keyToResultPositions.Add(key, responsesToReturn.Count - 1);
        }

        public void SetUserInfoToReturn(IUser user, Guid token)
        {
            userManager.User = user;
            userManager.Token = token;
        }

        private void AddVisitInformationIfAppropriate(Request request)
        {
            var authenticatedRequest = request as AuthenticatedRequest;

            if (authenticatedRequest != null)
            {
                authenticatedRequest.Visit = userManager.GetVisit();
            }
        }

        protected override void BeforeSendingRequests(IEnumerable<Request> requestsToProcess)
        {
            foreach (var request in requestsToProcess)
            {
                AddVisitInformationIfAppropriate(request);
            }
        }

        public override void Clear()
        {
            // this Stub can't clear the state because we have to be able to inspect the sent requests
            // during our tests
        }

        public override void Add(string key, Request request)
        {
            base.Add(key, request);
            keyToRequest[key] = request;
        }

        public TRequest GetRequest<TRequest>() where TRequest : Request
        {
            return (TRequest)SentRequests.First(r => r.GetType().Equals(typeof(TRequest)));
        }

        public TRequest GetRequest<TRequest>(string key) where TRequest : Request
        {
            return (TRequest)keyToRequest[key];
        }

        public bool HasRequest<TRequest>() where TRequest : Request
        {
            return SentRequests.Count(r => r.GetType().Equals(typeof(TRequest))) > 0;
        }
        
        protected override Response[] GetResponses(Request[] requestsToProcess)
        {
            BeforeSendingRequests(requestsToProcess);
            return responsesToReturn.ToArray();
        }
    }

  

    public class UserManagerStub : IClientSideUserManager
    {
        public IUser User { get; set; }
        public Guid Token { get; set; }

        public UserManagerStub()
        {
            // use these as the default values
            User = new UserDto();
            Token = Guid.NewGuid();
        }

        public IUser GetCurrentUserInfo()
        {
            return User;
        }

        public void StoreCurrentVisitInfo(Visit visit)
        {
            throw new System.NotImplementedException();
        }

        public Visit GetVisit()
        {
            return new Visit(Token, User);
        }
    }
}